home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacGames Sampler
/
PHT MacGames Bundle.iso
/
MacSource Folder
/
Samples from the CD
/
C and C++
/
sesame C ƒ
/
asample.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-10-06
|
19KB
|
653 lines
/* SAMPLE C PROGRAM */
/* This is just to show you how to get a Macintosh application */
/* using this compiler. Its style may not be the best, */
/* but it does show you how. For one thing, the whole thing */
/* should be broken into separate files and compiled separatly */
/* Separate compilation is just one of the neat things this */
/* compiler does. For more sample programs and documentation */
/* become a registered owner by paying for Sesame C. */
/* READ THE include file ~asample.inc for some general technical */
/* information on using this compiler */
/* ASAMPLE.C is a simple editor. It shows how to use almost every basic */
/* thing you can do with Sesame C and the Macintosh environment. */
/* It is simple and yet shows how you can get quite a lot from */
/* the Macintosh routines, such as menus, windows, scrollbars, */
/* and cut and paste textediting */
/* By the way, this takes quite a while to compile, mainly */
/* because it is fair sized and filled with comments. */
/* Separate compilation is really the way to go. */
#include ~asample.inc
/* Here are the program globals. In other files (if there were any), */
/* they would be declared extern (possibly in an include file) */
char seventrec[16],viewrect[8],pblock[100];
int windptr,tehnd,scrollhnd;
int applemenu, filemenu, editmenu,curtop;
start() /* Must start with start */
/* Used to initialize the Macintosh environment */
{
char qdglob[206];
TRAP(INITGRAF,&qdglob[202]:L); /* screwy address, but correct */
TRAP(INITFONTS);
flushevents(-1); /* flushevents is a registered routine, so we */
/* can't use the TRAP directive */
TRAP(INITWINDOWS);
TRAP(INITMENUS);
TRAP(INITDIALOG,0:L);
TRAP(TEINIT);
TRAP(INITCURSOR);
main();
}
/* This is a normal structure for a Macintosh program. */
/* First you do some setup stuff, then you loop though */
/* an event loop forever until you quite. You then */
/* should unsetup yourself if necessary. This program */
/* takes the lazy way out and just ends, letting the Macintosh */
/* finish up the cleanup */
main()
{
makemenu();
openwindow("untitled"); /* start off with an open window */
while(events()==0);
}
/* We just make a menu and keep it around. Good style includes */
/* enabling and disabling menu items depending on whether */
/* they can be used. */
makemenu()
{ char pascalstr[256];
ctopstr("*",pascalstr);
pascalstr[1]=20; /* set to apple icon */
applemenu=TRAP:L(NEWMENU,appleid:W,pascalstr);
ctopstr("Sample Sesame C Program;-;Modify at will",pascalstr);
TRAP(APPENDMENU,applemenu:L,pascalstr);
TRAP(INSERTMENU,applemenu:L,0:W); /* insert in front */
ctopstr("File",pascalstr);
filemenu=TRAP:L(NEWMENU,fileid:W,pascalstr);
ctopstr("New;Open;Close;Save;Save as...;Print;-;Quit/Q",pascalstr);
TRAP(APPENDMENU,filemenu:L,pascalstr);
TRAP(INSERTMENU,filemenu:L,0:W); /* insert in front */
ctopstr("Edit",pascalstr);
editmenu=TRAP:L(NEWMENU,editid:W,pascalstr);
ctopstr("Undo/Z;-;Cut/X;Copy/C;Paste/V;Clear;Select All/S",pascalstr);
TRAP(APPENDMENU,editmenu:L,pascalstr);
TRAP(INSERTMENU,editmenu:L,0:W); /* insert in front */
TRAP(DRAWMENUBAR);
}
openwindow(title) /* Opens a window with the specified title */
/* Note it does not open a file, just sets up the window */
/* Also note, that for simplicity this application only */
/* allows one window to be opened */
char title[];
{
char ptitle[64],boundrect[8],fontinfo[8];
/* The easiest way to define a window is with a resource. This */
/* is how you do it the old fashioned way */
/* C and Pascal strings are completely different. */
/* The Macintosh Toolbox understands only Pascal strings */
/* Everytime you use a TRAP that expects a string or returns */
/* a string you have to use these conversion functions. They are */
/* writen in assembler for speed's sake. They expect two addreses, */
/* one the address of the source string and the other the address of */
/* of the result string. Be careful! They do not check for any */
/* limits to the string sizes. P.S. the other routine is called ptocstr */
ctopstr(title,ptitle);
TRAP(SETRECT,&boundrect,5:W,45:W,507:W,337:W);
windptr=TRAP:L(NEWWINDOW,0,&boundrect,ptitle,1:B,4:W,-1,0:B,0);
TRAP(SETPORT,windptr);
TRAP(TEXTFONT,4:W);
TRAP(TEXTSIZE,9:W);
TRAP(SETRECT,&viewrect,4:W,5:W,482:W,290:W);
tehnd=TRAP:L(TENEW,&viewrect,&viewrect);
curtop=0;
TRAP(SETRECT,&boundrect,488:W,0:W,504:W,292:W);
scrollhnd=TRAP:L(NEWCONTROL,windptr:L,&boundrect,"",1:B,0:W,0:W,0:W,
16:W,0:L);
}
closewindow() /* Close the window opened by openwindow */
{
TRAP(TEDISPOSE,tehnd:L);
TRAP(DISPOSEWINDOW,windptr); /* simple */
windptr=0;
tehnd=0;
scrollhnd=0;
}
update()
{
TRAP(SETPORT,windptr);
TRAP(BEGINUPDATE,windptr);
TRAP(TEUPDATE,&viewrect,tehnd:L);
TRAP(DRAWCONTROLS,windptr:L);
TRAP(ENDUPDATE,windptr);
}
putachar(c)
char c;
{
int charpos;
TRAP(TEKEY,c:W,tehnd:L);
setscrollmax();
}
events()
{
int event;
if(tehnd)TRAP(TEIDLE,tehnd:L);
if(TRAP:B(GETNEXTEVENT,0xffff:W,&seventrec)) /* trap any event */
{
/* getword is a special function writen in assembler to get a */
/* two byte word from the specified address. It is a quick and */
/* useful way to get at some of the Macintosh data structures */
/* Going the other way, we have a routine call putword(address,value) */
/* that puts a word anywhere you want. It would be nice to */
/* have these for long words as well, though there is a way using */
/* C that we show you later. */
event=getword(&seventrec); /* get the event */
if(event==1)return domouse();
else if(event==3)return keydown();
else if(event==5)return keydown();
else if(event==6)update();
else if(event==8)activate();
}
return 0;
}
activate()
{
if(getword(&seventrec[14])&1)
{ /* activate */
TRAP(TEACTIVATE,tehnd);
}
else
{ /* deactivate */
TRAP(TEDEACTIVATE,tehnd);
}
}
keydown()
{
int modifiers;
char thekey;
modifiers=getword(&seventrec[14]);
thekey=seventrec[5];
if(modifiers&256)
{
return domenu(TRAP:L(MENUKEY,thekey:W));
}
else /* it a character so print it */
{
putachar(thekey); /* a return key */
}
return 0;
}
domouse()
{
int *evwhere,windowloc,wwindptr,mselected,where,whichpart,wcntlhnd;
evwhere=&seventrec[10];
where=*evwhere;
windowloc=TRAP:W(FINDWINDOW,where:L,&wwindptr:L);
if(windowloc==1) /* in menubar */
{
mselected=TRAP:L(MENUSELECT,where:L);
return domenu(mselected);
}
else if(windowloc==3) /* in content of window. This can be */
/* the text part or the scrollbar */
{
TRAP(GLOBALTOLOCAL,&where);
whichpart=TRAP:W(FINDCONTROL,where:L,windptr:L,&wcntlhnd:L);
if(whichpart==0)selecttext(where); /* in the text part */
/* now check if in the scrollbar parts */
else if(whichpart==20)doscroll(whichpart,-1); /* up button */
else if(whichpart==21)doscroll(whichpart,1); /* down button */
else if(whichpart==22)doscroll(whichpart,-pagelines); /* up page */
else if(whichpart==23)doscroll(whichpart,pagelines); /* down page */
else if(whichpart==129) /* in the thumb */
{
/* this next automatically tracks the mouse in */
/* the thumb, and sets the ctlvalue for you */
if(TRAP:W(TRACKCONTROL,scrollhnd:L,where:L,0:L)==129)
scroll();
}
}
return 0;
}
doscroll(whichpart,linestoscroll)
int whichpart,linestoscroll;
{
int wheremouse;
while(TRAP:B(STILLDOWN)) /* If you haven't let go of the mouse yet */
{
TRAP(GETMOUSE,&wheremouse); /* Where is it now? */
if(TRAP:W(TESTCONTROL,scrollhnd:L,wheremouse)==whichpart) /* there yet?*/
{
TRAP(HILITECONTROL,scrollhnd:L,whichpart:W); /* hilite the part */
TRAP(SETCTLVALUE,scrollhnd:L,curtop+linestoscroll:W);
scroll();
}
else TRAP(HILITECONTROL,scrollhnd:L,0:W); /* turn off hilite */
}
TRAP(HILITECONTROL,scrollhnd:L,0:W); /* make sure you turn off hilite */
}
selecttext(where)
int where;
{
if(TRAP:B(PTINRECT,where,&viewrect)) /* Is it in view? */
{
TRAP(TECLICK,where:L,0:B,tehnd); /* Extend is always false here */
}
}
/* This routine is boring, except that it shows how to use C */
/* to find the record a handle ultimately points to. Note here */
/* we are getting the address of the te record in terec. At the */
/* address + an offset of 94bytes is the number of lines in the */
/* te record */
setscrollmax()
{
int *temp;
char *terec;
if(tehnd!=0)
{
temp=tehnd;
terec=*temp; /* terec+94 is number of lines of text */
TRAP(SETCTLMAX,scrollhnd:L,getword(terec+94):W);
}
}
scroll()
{
int oldtop,numbtoscroll;
oldtop=curtop;
curtop=TRAP:W(GETCTLVALUE,scrollhnd:L);
numbtoscroll= (oldtop-curtop)*11; /* 11 is height of monaco 9 line */
/* scrolling 0 has been known to have strange effects, so we don't */
if(numbtoscroll!=0)TRAP(TESCROLL,0:W,numbtoscroll:W,tehnd:L);
}
domenu(menuinfo)
int menuinfo;
{
int menu,menuitem;
int in,volref;
char filename[64],pfilename[64];
menu=getword(&menuinfo);
menuitem=getword(&menuinfo+2);
if(menu==33) /* file menu */
{
if (menuitem==1)
{ /* new window */
if(windptr==0)openwindow("untitled");
}
else if(menuitem==2)
{ /* open file and window */
if(windptr==0)
{
volref=getfile(filename); /* returns 0 if cancelled */
if(volref)
{
openwindow(filename);
readfile(filename,volref);
}
}
}
else if(menuitem==3)
{
if(windptr!=0)
{
TRAP(GETWTITLE,windptr:L,&pfilename);
ptocstr(pfilename,filename); /* this seems dumb */
volref=putfile(filename,"Save the file as...",filename);
if(volref)
{
writefile(filename,volref);
}
closewindow(); /* Close the window even if cancel save. */
/* We really should go back to the window */
/* but this is kept simple. */
}
}
else if(menuitem==8) return 1; /* quitting time */
}
else if(menu==34) /* edit menu */
{
/* An editorial comment: The Mac really makes cutting and pasting a snap */
/* This next stuff is ridculously easy */
if(menuitem==3)TRAP(TECUT,tehnd:L);
else if(menuitem==4)TRAP(TECOPY,tehnd:L);
else if(menuitem==5)TRAP(TEPASTE,tehnd:L);
else if(menuitem==6)TRAP(TEDELETE,tehnd:L); /* clear */
else if(menuitem==7)TRAP(TESETSELECT,0:L,0XFFFF:L,tehnd:L); /* sel all*/
setscrollmax();
}
TRAP(HILITEMENU,0:W); /* unlite all menus items */
return 0;
}
/* Read a file into the te record. It reads the entire file all */
/* at once, which makes it rather fast. Everything here can be used */
/* to do the regular kind of stuff... open a file, read a line into a */
/* a buffer (rather than into the te record directly), read until you */
/* reach an end of file, eventually close the file. It is just a matter */
/* of creating space for a buffer and then using these same things to */
/* read into it a set amount repeatedly. I did it this way just to */
/* show how to do it fast and neat */
/* Readfile and writefile use an assembler routine, PBIO, that requires */
/* an address for the parameter block and a trap number. */
/* In effect PBIO gives you access to all the PB routines */
/* from the toolbox */
/* These routines really demonstrate how to play with non-simple */
/* structures using C and the getword/putword routines. It is a bit */
/* of a pain to get just right. If you have any problems, it is */
/* useful to look at the assembler listing that the compiler */
/* makes. You do this by selecting C Compile with Listing... instead of */
/* C Compile... Another idea is to write in C or assembler some */
/* simple conversion and assignment routines. (that's what I'm going to do) */
/* One thing to be careful of is that pointers know what kind of thing */
/* they point to. In this case laddress+20 returns an address 80 bytes */
/* offset from the value in laddress, while terec+20 returns an address */
/* offset 20 bytes. */
readfile(filename,volref)
char filename[];
int volref;
{
char pfilename[64];
char *terec;
int *laddress,*laddr2,retcode,i,filelen;
/* open the file */
for(i=0;i<100;i++)pblock[i]=0; /* initialize pblock */
ctopstr(filename,pfilename);
laddress=&pblock[18];
*laddress=pfilename; /* insert filename in pblock */
putword(&pblock[22],volref); /* insert volrefnumber */
pblock[26]=0; /* set permission to 0 */
pblock[27]=1; /* set read permission */
laddress=&pblock[28];
*laddress=0; /* set buffer to nil to use volume buffer */
retcode=pbio(0XA000,&pblock); /* open for read */
if(retcode!=0) return retcode; /* if error don't go on */
/* get filesize */
retcode=pbio(0XA011,&pblock); /* get eof */
laddress=&pblock[28]; /* size stored at offset 28 */
filelen=*laddress;
if(retcode!=0) return retcode; /* if error don't go on */
/* set text handlesize */
laddress=tehnd;
terec=*laddress;
laddress=terec+62; /* where the text handle is found */
retcode=sethandlesize(*laddress,filelen); /* resize the text in terec */
if(retcode!=0) return retcode; /* if error don't go on */
/* read the entire file */
laddress=tehnd;
terec=*laddress;
laddress=terec+62; /* get the text handle */
laddr2=*laddress; /* get address of start of text */
laddr2=*laddr2; /* I love handles, don't you? */
laddress=&pblock[32];
*laddress=laddr2; /* put start of text address into pblock */
laddress=&pblock[36];
*laddress=filelen;
putword(&pblock[44],0); /* no newline character */
laddress=&pblock[46];
*laddress=0; /* set offset to 0 */
retcode=pbio(0XA002,&pblock);
/* close the file */
retcode=pbio(0XA001,&pblock); /* close it */
recaltext(filelen);
}
recaltext(filelen)
int filelen;
{
int *laddress;
char *terec;
laddress=tehnd;
terec=*laddress;
putword(terec+60,filelen);
TRAP(TECALTEXT,tehnd:L);
TRAP(TESETSELECT,0:L,0:L,tehnd:L); /* set select to start */
setscrollmax();
}
/* write the entire terecord out to a disk file */
writefile(filename,volref)
char filename[];
int volref;
{
char pfilename[64];
char *terec;
int *laddress,*laddr2,retcode,i,filelen;
/* open the file */
ctopstr(filename,pfilename);
laddress=&pblock[18];
*laddress=pfilename; /* insert filename in pblock */
putword(&pblock[22],volref); /* insert volrefnumber */
pblock[26]=0; /* set permission to 0 */
pblock[27]=2; /* set write permission */
laddress=&pblock[28];
*laddress=0; /* set buffer to nil to use volume buffer */
retcode=pbio(0XA000,&pblock); /* open for write */
/* if file doesn't exist retcode=-43, so create it */
if(retcode==-43)retcode=createfile(filename,volref);
if(retcode!=0) return retcode; /* if error don't go on */
/*write the entire file */
laddress=tehnd;
terec=*laddress;
laddress=terec+62; /* get the text handle */
laddr2=*laddress; /* get address of start of text */
filelen=getword(terec+60); /* get cur text length from terec */
laddr2=*laddr2; /* I love handles, don't you? */
laddress=&pblock[32];
*laddress=laddr2; /* put start of text address into pblock */
laddress=&pblock[36];
*laddress=filelen;
putword(&pblock[44],1); /* set pos mode for start of file */
laddress=&pblock[46];
*laddress=0; /* set offset to 0 */
retcode=pbio(0XA003,&pblock);
/* set the file eof */
laddress=&pblock[28];
laddr2=&pblock[40];
*laddress=*laddr2; /* store the io count from write */
retcode=pbio(0XA012,&pblock);
/* close the file */
retcode=pbio(0XA001,&pblock); /* close it */
/* flush the volume */
laddress=&pblock[18];
*laddress=0; /* set name to 0, volref is enough */
retcode=pbio(0XA013,&pblock); /* flush away */
}
createfile(filename,volref)
char filename[];
int volref;
{
char pfilename[64];
char *terec;
int *laddress,*laddr2,retcode,i,filelen;
/* open the file */
ctopstr(filename,pfilename);
laddress=&pblock[18];
*laddress=pfilename; /* insert filename in pblock */
putword(&pblock[22],volref); /* insert volrefnumber */
pblock[26]=0; /* set version to 0 */
retcode=pbio(0XA008,&pblock); /* create it */
if(retcode!=0) return retcode;
/* get the fileinfo */
laddress=&pblock[18];
*laddress=pfilename; /* insert filename in pblock */
putword(&pblock[22],volref); /* insert volrefnumber */
pblock[26]=0; /* set version to 0 */
putword(&pblock[28],0); /* set dir index to 0 */
retcode=pbio(0XA00C,&pblock); /* get file info */
/* set the fileinfo */
/* use the fileinfo we just got, and set type to text */
pblock[32]='T';
pblock[33]='E';
pblock[34]='X';
pblock[35]='T';
/* you could set the creator to something here */
retcode=pbio(0XA00D,&pblock); /* set file info */
/* now try opening it again */
laddress=&pblock[18];
*laddress=pfilename; /* insert filename in pblock */
putword(&pblock[22],volref); /* insert volrefnumber */
pblock[26]=0; /* set permission to 0 */
pblock[27]=2; /* set write permission */
laddress=&pblock[28];
*laddress=0; /* set buffer to nil to use volume buffer */
retcode=pbio(0XA000,&pblock); /* open for write */
return retcode;
}
/* output a decimal number */
outdec(n)
int n;
{
if(n<0)
putachar('-');
else n = -n;
outint(n);
/* end outdec */}
outint(n)
int n;
{ int q;
q = n/10;
if(q) outint(q);
putachar('0'-(n-q*10));
/* end outint */}
wait()
{
int event;
while(1)
{
if(TRAP:B(GETNEXTEVENT,0XFFFF:W,&seventrec)) /* trap any event */
{
event=getword(&seventrec);
if(event==1)break; /* mouse */
if(event==3)break; /* keydown */
}
}
}